package com.ziytek.web.citizen.service;

import com.google.gson.Gson;
import com.ziytek.web.citizen.caffeine.CachePutOrGet;
import com.ziytek.web.citizen.config.caffeine.CaffeineUtil;
import com.ziytek.web.citizen.constant.NumConstant;
import com.ziytek.web.citizen.constant.ServerConstant;
import com.ziytek.web.citizen.constant.TableConstant;
import com.ziytek.web.citizen.enums.ErrorTypeEnum;
import com.ziytek.web.citizen.enums.StepTypeNoEnum;
import com.ziytek.web.citizen.mapper.BatchNoMapper;
import com.ziytek.web.citizen.mapper.OperationDetailMapper;
import com.ziytek.web.citizen.mapper.TableMapper;
import com.ziytek.web.citizen.model.bean.CapStatsVo;
import com.ziytek.web.citizen.model.bean.CommandIssuedSuccess;
import com.ziytek.web.citizen.model.vo.RealTimeVo;
import com.ziytek.web.citizen.model.vo.StatsDo;
import com.ziytek.web.citizen.util.KeyUtil;
import com.ziytek.web.citizen.util.StringUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

/**
 * @author fengh
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ChannelStatsService {

    private final Gson gson;
    private final TableMapper tableMapper;
    private final CachePutOrGet cachePutOrGet;
    private final BatchNoMapper batchNoMapper;
    private final BatchNoService batchNoService;
    private final CompressionService compressionService;
    private final OperationDetailMapper operationDetailMapper;
    private final OperationVoCacheService operationVoCacheService;

    private Pair<RealTimeVo, StatsDo> getEndStatsDo(CapStatsVo stats, String cabinetNo, String operaId) {
        if (stats == null) {
            return Pair.of(null, null);
        }

        var sp = stats.k.split(CaffeineUtil.CACHE_KEY_SYMBOL);
        var boardNo = sp[NumConstant.INT_ONE];
        var channelNo = sp[NumConstant.INT_TWO];
        var vdo = new StatsDo();
        var vo = new RealTimeVo();
        vo.setC(stats.getI());
        vo.setV(stats.getV());
        vo.setVo(stats.getVo());
        vo.setTs(stats.getTs());
        vo.setAc(stats.getAc());
        vo.setCpa(stats.getC());
        vo.setEt(stats.getEt());
        vo.setCty(stats.getCty());
        // 状态设置为已完成
        vo.setT(ErrorTypeEnum.EXECUTION_COMPLETED.getCode());
        vo.setCn(Integer.parseInt(cabinetNo));
        vo.setBn(boardNo == null ? NumConstant.INT_ZERO : Integer.parseInt(boardNo));
        vo.setCnn(channelNo == null ? NumConstant.INT_ZERO : Integer.parseInt(channelNo));
        byte[] bytes = gson.toJson(vo).getBytes(StandardCharsets.UTF_8);

        try {
            byte[] data = compressionService.compress(bytes);
            vdo.setData(data);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        vdo.setBn(vo.getBn());
        vdo.setCn(vo.getCn());
        vdo.setCnn(vo.getCnn());
        vdo.setOperateId(operaId);
        vdo.setTime((long) vo.getTs());
        vdo.setCreateTime(System.currentTimeMillis());
        vdo.setStatus(ErrorTypeEnum.EXECUTION_COMPLETED.getCode());
        return Pair.of(vo, vdo);
    }


    public void allChannelStats(CommandIssuedSuccess command) {
        if (null == command || command.isSingleChannel()) {
            return;
        }

        var cabinetNo = String.valueOf(Integer.parseInt(String.valueOf(command.getReqCabinetNo())));
        var operationDetailList = operationDetailMapper.findDetailNotSingleType(cabinetNo, ServerConstant.SINGLE_TYPE_ALL);
        log.info("执行终止allChannelStats保存:{}", operationDetailList.size());
        if (CollectionUtils.isEmpty(operationDetailList)) {
            return;
        }

        int count = NumConstant.INT_ZERO;
        var batchNoString = "";
        for (var od : operationDetailList) {
            var key = command.getReqCabinetNo() + CaffeineUtil.CACHE_KEY_SYMBOL + od.getBoardAddress() + CaffeineUtil.CACHE_KEY_SYMBOL + od.getCellNum();
            var s = cachePutOrGet.getStatsCache(key);
            var isDischarge = s != null && (StepTypeNoEnum.STEP_TYPE_CCD_NUM.getCode().equalsIgnoreCase(s.getCty()) ||
                    StepTypeNoEnum.STEP_TYPE_CPD_NUM.getCode().equalsIgnoreCase(s.getCty()) ||
                    StepTypeNoEnum.STEP_TYPE_CRD_NUM.getCode().equalsIgnoreCase(s.getCty()));

            // 不是正常状态
            boolean notNormalStatus = null != s && (ErrorTypeEnum.LEISURE.getCode() == s.getT() || ErrorTypeEnum.WAITING.getCode() == s.getT());
            // 不是放电工步，不保存放电容量数据 ,或者不是正常状态的容量数据不保存
            boolean isNotSave = (!isDischarge) || notNormalStatus;
            if (isNotSave) {
                //log.info("isNotSave isDischarge:{},notNormalStatus:{}-od:{}-stats[{}]", isDischarge, notNormalStatus, gson.toJson(od), gson.toJson(s));
                continue;
            }

            //  todo 放电数据 保存放电容量数据 放电结束就保存，不能到工艺最后保存
            Pair<RealTimeVo, StatsDo> pair = getEndStatsDo(s, command.getReqCabinetNo(), od.getOperationId());
            //log.error("so，{} key:{}", so, key);
            if (null == pair || null == pair.getRight()) {
                continue;
            }

            StatsDo so = pair.getRight();
            RealTimeVo rvo = pair.getLeft();
            // 新增批次号
            var opKey = KeyUtil.commandOperateKey(cabinetNo, od.getBoardAddress(), od.getCellNum());
            var vo = operationVoCacheService.getOperationVo(opKey);
            if (null != vo && StringUtil.isNotEmpty(vo.getBatchNo())) {
                so.setBatchNo(vo.getBatchNo());
                batchNoString = vo.getBatchNo();
            }

            // 保存放电容量数据
            int result = tableMapper.addSingleStats(TableConstant.TABLE_REAL_TIME_STATS, so);
            count += 1;

            if (null != rvo) {
                // 保存放电容量数据
                var tableName = TableConstant.TABLE_REAL_TIME + od.getBoardAddress();
                var rd = tableMapper.queryRealTimeLastAndBatchNo(tableName, Integer.parseInt(cabinetNo), od.getBoardAddress(), od.getCellNum(), batchNoString);

                if (null != rd) {
                    byte[] data;
                    try {
                        data = compressionService.decompress(rd.getData());
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }

                    var v1 = gson.fromJson(new String(data, StandardCharsets.UTF_8), RealTimeVo.class);
                    var isDischargeData = v1 != null && (StepTypeNoEnum.STEP_TYPE_CCD_NUM.getCode().equalsIgnoreCase(s.getCty()) ||
                            StepTypeNoEnum.STEP_TYPE_CPD_NUM.getCode().equalsIgnoreCase(s.getCty()) ||
                            StepTypeNoEnum.STEP_TYPE_CRD_NUM.getCode().equalsIgnoreCase(s.getCty()));
                    if (isDischargeData) {
                        v1.setC(rvo.getC());
                        v1.setV(rvo.getV());
                        //v1.setC(8);
                        //v1.setV(3500);
                        byte[] bytes = gson.toJson(v1).getBytes(StandardCharsets.UTF_8);
                        try {
                            byte[] dataCompress = compressionService.compress(bytes);
                            rd.setData(dataCompress);
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }

                        // 更新
                        try {
                            // 先删除在新增
                            tableMapper.deleteSingleRealTime(tableName, rd.getId());
                            tableMapper.addSingleRealTime(tableName, rd);
                        } catch (Exception e) {
                            log.error("error:{} errorMsg: ", gson.toJson(rd), e);
                        }
                    }
                }
            }
        }

        log.info("执行终止allChannelStats保存完成:{}", count);
        if (count > NumConstant.INT_ZERO) {
            var batchNo = batchNoMapper.queryLastBatchNoAndCabinetNo(Integer.parseInt(cabinetNo), batchNoString);
            if (null != batchNo && null != batchNo.getHasCapacity() && NumConstant.INT_ONE != batchNo.getHasCapacity()) {
                batchNo.setHasCapacity(NumConstant.INT_ONE);
                batchNoService.updateBatchNo(batchNo);
            }
        }
    }

    public void singleStats(CommandIssuedSuccess command) {
        if (null == command || !command.isSingleChannel()) {
            return;
        }

        var boardNo = command.getBoardNo();
        var cabinetNo = String.valueOf(Integer.parseInt(String.valueOf(command.getReqCabinetNo())));
        var odOne = operationDetailMapper.findOneDetailByCellNum(cabinetNo, boardNo, command.getChannelNo());
        if (odOne == null) {
            return;
        }

        // 保存单个通道放电容量数据
        var key = command.getReqCabinetNo() + CaffeineUtil.CACHE_KEY_SYMBOL + odOne.getBoardAddress() + CaffeineUtil.CACHE_KEY_SYMBOL + odOne.getCellNum();
        var s = cachePutOrGet.getStatsCache(key);
        var isDischarge = s != null && (StepTypeNoEnum.STEP_TYPE_CCD_NUM.getCode().equalsIgnoreCase(s.getCty()) ||
                StepTypeNoEnum.STEP_TYPE_CPD_NUM.getCode().equalsIgnoreCase(s.getCty()) ||
                StepTypeNoEnum.STEP_TYPE_CRD_NUM.getCode().equalsIgnoreCase(s.getCty()));

        // 不是正常状态
        boolean notNormalStatus = null != s && (ErrorTypeEnum.LEISURE.getCode() == s.getT() || ErrorTypeEnum.WAITING.getCode() == s.getT());
        // 不是放电工步，不保存放电容量数据 ,或者不是正常状态的容量数据不保存
        boolean isNotSave = (!isDischarge) || notNormalStatus;
        if (isNotSave) {
            //log.info("不是放电工步,key:{},容量数据:{},状态:{}", key, s == null, s != null ? s.getT() : "");
            log.info("不是放电工步 isNotSave isDischarge:{},notNormalStatus:{}-odOne:{}-stats[{}]", isDischarge, notNormalStatus, gson.toJson(odOne), gson.toJson(s));
            return;
        }

        Pair<RealTimeVo, StatsDo> pair = getEndStatsDo(s, command.getReqCabinetNo(), odOne.getOperationId());
        //log.error("so，{} key:{}", so, key);
        if (null == pair || null == pair.getRight()) {
            return;
        }

        StatsDo so = pair.getRight();
        RealTimeVo rvo = pair.getLeft();
        var batchNoString = "";
        // 新增批次号
        var opKey = KeyUtil.commandOperateKey(cabinetNo, odOne.getBoardAddress(), odOne.getCellNum());
        var vo = operationVoCacheService.getOperationVo(opKey);
        if (vo != null && StringUtil.isNotEmpty(vo.getBatchNo())) {
            so.setBatchNo(vo.getBatchNo());
            batchNoString = vo.getBatchNo();
        }
        // 保存放电容量数据
        tableMapper.addSingleStats(TableConstant.TABLE_REAL_TIME_STATS, so);

        var batchNo = batchNoMapper.queryLastBatchNoAndCabinetNo(Integer.parseInt(cabinetNo), batchNoString);
        log.info("执行终止保存完成:{}", gson.toJson(batchNo));
        if (null != batchNo) {
            batchNo.setHasCapacity(NumConstant.INT_ONE);
            batchNoService.updateBatchNo(batchNo);
        }

        if (null != rvo) {
            // 保存放电容量数据
            var tableName = TableConstant.TABLE_REAL_TIME + odOne.getBoardAddress();
            var rd = tableMapper.queryRealTimeLastAndBatchNo(tableName, Integer.parseInt(cabinetNo), odOne.getBoardAddress(), odOne.getCellNum(), batchNoString);

            if (null != rd) {
                byte[] data;
                try {
                    data = compressionService.decompress(rd.getData());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }

                var v1 = gson.fromJson(new String(data, StandardCharsets.UTF_8), RealTimeVo.class);
                var isDischargeData = v1 != null && (StepTypeNoEnum.STEP_TYPE_CCD_NUM.getCode().equalsIgnoreCase(s.getCty()) ||
                        StepTypeNoEnum.STEP_TYPE_CPD_NUM.getCode().equalsIgnoreCase(s.getCty()) ||
                        StepTypeNoEnum.STEP_TYPE_CRD_NUM.getCode().equalsIgnoreCase(s.getCty()));
                if (!isDischargeData) {
                    return;
                }

                v1.setC(rvo.getC());
                v1.setV(rvo.getV());
                byte[] bytes = gson.toJson(v1).getBytes(StandardCharsets.UTF_8);
                try {
                    byte[] dataCompress = compressionService.compress(bytes);
                    rd.setData(dataCompress);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }

                // 更新
                try {
                    // 先删除在新增
                    tableMapper.deleteSingleRealTime(tableName, rd.getId());
                    tableMapper.addSingleRealTime(tableName, rd);
                } catch (Exception e) {
                    log.error("error:{}", gson.toJson(rd));
                }
            }
        }

    }

}
